package com.ssy.lingxi.report.utils;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.ssy.lingxi.component.redis.service.IRedisUtils;
import com.ssy.lingxi.report.constant.Constants;
import com.ssy.lingxi.report.service.*;
import com.ssy.lingxi.report.service.tally.ITallyReportService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * 定时器
 * @author 伍将
 * @date 2020/11/4
 * @version 2.0.0
 */
@Component
@EnableScheduling
@EnableAsync
public class Scheduler {

    @Resource
    private IActiveMerchantService activeMerchantService;

    @Resource
    private IPopularShopService popularShopService;

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    @Resource
    private IMemberReportService memberReportService;

    @Resource
    private IOrderReportService orderReportService;

    @Resource
    private INewlyAddedDayReportService newlyAddedDayReportService;

    @Resource
    private ITallyReportService tallyReportService;

    @Resource
    private IPlatformSettlementService platformSettlementService;

    @Resource
    private IMemberSettlementService memberSettlementService;

    @Resource
    private IRedisUtils redisUtils;

    @Resource
    private IContractReportService contractReportService;

    private static final Logger logger = LoggerFactory.getLogger(Scheduler.class);

    /**
     * 定时任务
     * 每天0:20执行
     * @author 伍将
     * @date 2020/11/24
     **/
    @Async
    @Scheduled(cron = "0 20 00 ? * *")
    public void ScheduledTask() {

        String key = com.ssy.lingxi.common.constant.Constants.REDIS_KEY_REPORT_TASK;
        // 检查定时服务是否正在执行，如正在执行则退出任务
        Object obj = redisUtils.get(key, com.ssy.lingxi.common.constant.Constants.REDIS_REPORT_INDEX);
        if (obj != null) {
            Boolean isExecute = (Boolean) obj;
            if (isExecute) {
                logger.info("定时任务正在执行...");
                return;
            }
        }
        // 设置定时任务正在执行
        redisUtils.set(key, true,10*60L, com.ssy.lingxi.common.constant.Constants.REDIS_REPORT_INDEX);

        try {
            activeMerchantTask();
        } catch (Exception e) {
            logger.info("活跃商户定时任务失败：{}", e.getMessage());
        }
        try {
            popularShopTask();
        } catch (Exception e) {
            logger.info("人气店铺定时任务失败：{}", e.getMessage());
        }
        try {
            memberDayRegisterTask();
        } catch (Exception e) {
            logger.info("日注册会员定时任务失败：{}", e.getMessage());
        }
        try {
            memberMonthRegisterTask();
        } catch (Exception e) {
            logger.info("月注册会员定时任务失败：{}", e.getMessage());
        }
        try {
            orderDayReportTask();
        } catch (Exception e) {
            logger.info("日订单统计定时任务失败：{}", e.getMessage());
        }
        try {
            orderMonthReportTask();
        } catch (Exception e) {
            logger.info("月订单统计定时任务失败：{}", e.getMessage());
        }
        try {
            newlyAddedDayReportTask();
        } catch (Exception e) {
            logger.info("新增日报表定时任务失败：{}", e.getMessage());
        }
        try {
            memberSettlement();
        } catch (Exception e) {
            logger.info("统计会员结算定时任务失败：{}", e.getMessage());
        }
        try {
            platformSettlement();
        } catch (Exception e) {
            logger.info("统计平台结算定时任务失败：{}", e.getMessage());
        }
        try {
            // 票据任务需放置平台与会员结算之后，因为统计数据需要使用前置统计结果
            memberReceiptInvoiceReport();
        } catch (Exception e) {
            logger.info("统计会员票据结算定时任务失败：{}", e.getMessage());
        }
        try {
            // 会员票据通知需放置平台与会员结算之后，因为统计数据需要使用前置统计结果
            memberReceiptInvoiceNotice();
        } catch (Exception e) {
            logger.info("统计会员票据通知定时任务失败：{}", e.getMessage());
        }
        try {
            // 首页统计计数放置最后，确保其他数据已统计完再做汇总计算
            statisticsTally();
        } catch (Exception e) {
            logger.info("统计计数定时任务失败：{}", e.getMessage());
        }
        try {
            // 平台首页:采购统计：统计整个平台昨天的合同数量与金额
            contractReportService.newlyAddedDayContractReportTask();
        } catch (Exception e) {
            logger.error("新增采购统计[合同]日报表定时任务失败;", e);
        }
        try {
            // 采购门户: 采购统计
            memberReportService.newlyAddedDayPurchaseReportTask();
        } catch (Exception e) {
            logger.error("新增采购日报表定时任务失败;", e);
        }
        // 设置定时任务非执行状态
        logger.info("定时任务准备解锁>>>");
        redisUtils.set(key, false, com.ssy.lingxi.common.constant.Constants.REDIS_REPORT_INDEX);
        logger.info("定时任务准备解锁完成>>>");
    }

    /**
     * 活跃商户定时任务
     * @author 伍将
     * @date 2020/11/4
     **/
    private void activeMerchantTask() {

        logger.info("活跃商户定时任务开启：" + dateFormat.format(new Date()));

        // 查询前30天数据
        Long startTime = DateUtil.offsetDay(DateUtil.date(), -31).getTime();

        // 查询top10
        Integer count = 10;

        activeMerchantService.ActiveMerchantTask(startTime, count);

        logger.info("活跃商户定时任务结束：" + dateFormat.format(new Date()));
    }

    /**
     * 人气店铺定时任务
     * @author 伍将
     * @date 2020/11/4
     **/
    private void popularShopTask() {

        logger.info("人气店铺定时任务开启：" + dateFormat.format(new Date()));

        // 查询前7天数据
        Long startTime = DateUtil.offsetDay(DateUtil.date(), -8).getTime();

        popularShopService.popularShopTask(startTime, Constants.STATISTICS_POPULAR_SHOP_COUNT);

        logger.info("人气店铺定时任务结束：" + dateFormat.format(new Date()));
    }

    /**
     * 日注册会员统计任务
     * @author 伍将
     * @date 2020/11/9
     **/
    private void memberDayRegisterTask() {

        logger.info("日注册会员定时任务开启：" + dateFormat.format(new Date()));

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 查询前1天数据
        LocalDateTime startTime = LocalDateTime.parse(
                DateUtil.offsetDay(DateUtil.date(), -1)
                        .toString("yyyy-MM-dd 00:00:00")
                , formatter);
        LocalDateTime endTime = LocalDateTime.parse(
                DateUtil.offsetDay(DateUtil.date(), -1)
                        .toString("yyyy-MM-dd 23:59:59")
                , formatter);

        memberReportService.memberRegisterDayReport(startTime, endTime);

        logger.info("日注册会员定时任务结束：" + dateFormat.format(new Date()));
    }

    /**
     * 月注册会员统计任务
     * @author 伍将
     * @date 2020/11/9
     **/
    private void memberMonthRegisterTask() {

        logger.info("月注册会员定时任务开启：" + dateFormat.format(new Date()));

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 查询前1天所在整月数据
        LocalDateTime startTime = LocalDateTime.parse(
                DateUtil.format(TimeUtil.getMonthFirstDay(DateUtil.offsetDay(DateUtil.date(), -1))
                        , "yyyy-MM-dd 00:00:00")
                , formatter);
        LocalDateTime endTime = LocalDateTime.parse(
                DateUtil.format(TimeUtil.getMonthLastDay(DateUtil.offsetDay(DateUtil.date(), -1))
                        , "yyyy-MM-dd 23:59:59")
                , formatter);

        memberReportService.memberRegisterMonthReport(startTime, endTime);

        logger.info("月注册会员定时任务结束：" + dateFormat.format(new Date()));
    }

    /**
     * 订单日统计任务
     * @author 伍将
     * @date 2020/11/10
     **/
    private void orderDayReportTask() {

        logger.info("订单日报表定时任务开启：" + dateFormat.format(new Date()));

        // 查询前1天数据
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        LocalDateTime startTime = LocalDateTime.parse(
                DateUtil.offsetDay(DateUtil.date(), -1).toString("yyyy-MM-dd 00:00:00")
                , formatter);
        LocalDateTime endTime = LocalDateTime.parse(
                DateUtil.offsetDay(DateUtil.date(), -1).toString("yyyy-MM-dd 23:59:59")
                , formatter);


        orderReportService.orderDayReport(startTime, endTime);

        logger.info("订单日报表定时任务结束：" + dateFormat.format(new Date()));
    }

    /**
     * 订单月统计任务
     * @author 伍将
     * @date 2020/11/10
     **/
    private void orderMonthReportTask() {

        logger.info("订单月报表定时任务开启：" + dateFormat.format(new Date()));

        // 查询前1天所在整月数据
        Date startDate = TimeUtil.getMonthFirstDay(DateUtil.parse(DateUtil.offsetDay(DateUtil.date(), -1).toString("yyyy-MM-dd 00:00:00")));
        Date endDate = TimeUtil.getMonthLastDay(DateUtil.parse(DateUtil.offsetDay(DateUtil.date(), -1).toString("yyyy-MM-dd 23:59:59")));
        ZoneId zoneId = ZoneId.systemDefault();

        Instant startInstant = startDate.toInstant();
        Instant endInstant = endDate.toInstant();

        LocalDateTime startTime = startInstant.atZone(zoneId).toLocalDateTime();
        LocalDateTime endTime = endInstant.atZone(zoneId).toLocalDateTime();

        orderReportService.orderMonthReport(startTime, endTime);

        logger.info("订单月报表定时任务结束：" + dateFormat.format(new Date()));
    }

    /**
     * 新增日报表任务
     * @author 伍将
     * @date 2020/11/12
     **/
    private void newlyAddedDayReportTask() {

        logger.info("日新增报表定时任务开启：" + dateFormat.format(new Date()));

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 查询前1天数据
        LocalDateTime startTime = LocalDateTime.parse(
                DateUtil.offsetDay(DateUtil.date(), -1)
                        .toString("yyyy-MM-dd 00:00:00")
                , formatter);
        LocalDateTime endTime = LocalDateTime.parse(
                DateUtil.offsetDay(DateUtil.date(), -1)
                        .toString("yyyy-MM-dd 23:59:59")
                , formatter);

        newlyAddedDayReportService.newlyAddedDayReport(startTime, endTime);

        logger.info("日新增报表定时任务结束：" + dateFormat.format(new Date()));
    }

    /**
     * 统计计数
     * @author 伍将
     * @date 2020/11/23
     **/
    private void statisticsTally() {

        logger.info("计数统计报表定时任务开启：" + dateFormat.format(new Date()));

        tallyReportService.statisticsTally();

        logger.info("计数统计表定时任务结束：" + dateFormat.format(new Date()));
    }

    /**
     * 会员结算
     * @author 伍将
     * @date 2020/12/15
     **/
    private void memberSettlement() {
        logger.info("会员结算定时任务开启：" + dateFormat.format(new Date()));

        memberSettlementService.memberSettlementReport(DateTime.now());

        logger.info("会员结算定时任务结束：" + dateFormat.format(new Date()));
    }

    /**
     * 平台结算
     * @author 伍将
     * @date 2020/12/15
     **/
    private void platformSettlement() {
        logger.info("平台结算定时任务开启：" + dateFormat.format(new Date()));
        platformSettlementService.settlementReport(DateTime.now());
        logger.info("平台结算定时任务结束：" + dateFormat.format(new Date()));
    }

    /**
     * 会员票据结算
     * @author 伍将
     * @date 2020/12/16
     **/
    private void memberReceiptInvoiceReport() {
        logger.info("会员票据结算定时任务开启：" + dateFormat.format(new Date()));
        memberSettlementService.memberReceiptInvoiceReport();
        logger.info("会员票据结算定时任务结束：" + dateFormat.format(new Date()));
    }

    /**
     * 会员票据通知
     * @author 伍将
     * @date 2020/12/22
     **/
    private void memberReceiptInvoiceNotice() {
        logger.info("会员票据通知定时任务开启：" + dateFormat.format(new Date()));
        memberSettlementService.memberReceiptInvoiceNotice();
        logger.info("会员票据通知定时任务结束：" + dateFormat.format(new Date()));
    }

}
